﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using ECCIT.Extension.Weibo_v1.Common;
using ECCIT.Extension.Weibo_v1.Configuration;
using ECCIT.Extension.Weibo_v1.Model;
using ECCIT.Extension.Weibo_v1.Lib;
using NUnit.Framework;

namespace ECCIT.Extension.Weibo_v1.Lib.Test
{
    using Environment = Configuration.Environment;

    [TestFixture]
    public class MicroblogTest
    {
        private const long currentTestUserID = 2393053602;
        private const long AldrickUserID = 2527935682;
        private const long TestUserID = 1226825014;

        [SetUp]
        public void Init()
        {
            try
            {
                //Microblog.Login("someone_ly@hotmail.com", "Honey815!");
                Microblog.Login("dwcandy@yahoo.cn", "candyhoney815!");

                Environment.ResponseError += new EventHandler<ResponseErrorEventArgs>(Environment_ResponseError);
            }
            catch (MicroblogException ex)
            {
                Assert.Fail(string.Format("ErrorCode: {0}. Error Message: {1}.", ex.ErrorCode, ex.Message));
            }
        }

        private void Environment_ResponseError(object sender, ResponseErrorEventArgs e)
        {
            Console.WriteLine("An error response for {0}: {1}", e.ErrorData.RequestUri, e.ErrorData.Exception.Message);
        }

        [Test]
        public void TestVerifyCredential()
        {
            var user = Microblog.VerifyCredential();

            Assert.IsNotNull(user);
            Assert.AreEqual(currentTestUserID, user.ID);
        }

        [Test]
        public void TestGetUserSearchSuggestions()
        {
            var suggestions = Microblog.GetUserSearchSuggestions("sina");

            Assert.IsNotNull(suggestions);
        }

        [Test]
        public void TestSearchStatuses()
        {
            var result = Microblog.SearchStatuses("MicroblogAPI", null, null, null, null, null, null, null, null, null, true);

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestStatusLifecycle()
        {
            var rnd = new Random();
            var statusInfo = new UpdateStatusInfo();
            statusInfo.Status = "#MicroblogAPI# This is a test " + rnd.Next().ToString();
            statusInfo.Latitude = 125.12f;
            statusInfo.Longitude = 125.12f;
            var status = Microblog.PostStatus(statusInfo);
            Assert.IsNotNull(status);
            Assert.AreEqual(statusInfo.Status, status.Text);

            // Get status
            var retrievedStatus = Microblog.GetStatus(status.ID);
            Assert.AreEqual(statusInfo.Status, retrievedStatus.Text);

            // Repost as comment
            var repostStatusText = "#MicroblogAPI# This is a repost " + rnd.Next().ToString();
            var repostedStatus = Microblog.Forward(retrievedStatus.ID, repostStatusText, true);
            Assert.IsNotNull(repostedStatus);
            Assert.AreEqual(repostStatusText, repostedStatus.Text);

            // Comment
            var commentText = "This is a comment " + rnd.Next().ToString();
            var comment = Microblog.Comment(retrievedStatus.ID, commentText);
            Assert.IsNotNull(comment);
            Assert.AreEqual(commentText, comment.Text);

            // Reply comment
            var replyCommentText = "Reply comment " + rnd.Next().ToString();
            var replyComment = Microblog.ReplyComment(comment.ID, replyCommentText, retrievedStatus.ID);
            Assert.IsNotNull(replyComment);
            Assert.IsTrue(replyComment.Text.Contains(replyCommentText));

            var commentsCounter = Microblog.GetCountersOfCommentNForward(new long[] { status.ID, repostedStatus.ID });
            Assert.IsNotNull(replyComment);
            Assert.AreEqual(2, commentsCounter.Items.Count);

            // Delete comment
            var destroiedComment = Microblog.DeleteComment(comment.ID);
            Assert.AreEqual(comment.ID, destroiedComment.ID);

            // Delete another comment
            var destroiedReplyComments = Microblog.DeleteComments(new long[] { replyComment.ID });
            Assert.AreEqual(1, destroiedReplyComments.Items.Count);

            Microblog.DeleteStatus(status.ID);
            Microblog.DeleteStatus(repostedStatus.ID);
        }

        [Test]
        [ExpectedException(typeof(MicroblogException))]
        public void TestDirectMessageLifecycle()
        {
            // No permission to call DM APIs.
            var dMsgs = Microblog.GetDirectMessages();
            Assert.IsNotNull(dMsgs);
        }

        [Test]
        public void TestResetCounter()
        {
            Microblog.ResetCounter(CounterType.Comment);
        }

        [Test]
        public void TestGetEmotions()
        {
            var emotions = Microblog.GetEmotions(EmotionType.Cartoon, "twname");

            Assert.IsNotNull(emotions);
        }

        [Test]
        public void TestGetCommentsTimeline()
        {
            var result = Microblog.GetCommentsTimeline();

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetCommentsByMe()
        {
            var result = Microblog.GetCommentsByMe();

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetCommentsToMe()
        {
            var result = Microblog.GetCommentsToMe();

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetUnreadInfo()
        {
            var result = Microblog.GetUnreadInfo();

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetUserInfo()
        {
            var user = Microblog.GetUserInfo(AldrickUserID);

            Assert.IsNotNull(user);
            Assert.AreEqual(AldrickUserID, user.ID);
        }

        [Test]
        public void TestGetUserInfoByName()
        {
            var user = Microblog.GetUserInfo("dwcandy");

            Assert.IsNotNull(user);
            Assert.AreEqual(AldrickUserID, user.ID);
        }

        [Test]
        public void TestGetUserStatuses()
        {
            var result = Microblog.GetUserStatuses(currentTestUserID);

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestLoopGetUserStatuses()
        {
            Statuses statuses = Microblog.GetUserStatuses(currentTestUserID, null, null, null, 200, StatusType.All, false);
            int count = statuses.Items.Count;
            int totalCount = statuses.TotalCount;
            StatusInfo firstStatus = statuses.Items[count - 1];
            long? maxID = firstStatus.ID;

            statuses = Microblog.GetUserStatuses(currentTestUserID, null, maxID, null, 200, StatusType.All, false);
            count = statuses.Items.Count;
            totalCount = statuses.TotalCount;
            firstStatus = statuses.Items[count - 1];

            Assert.IsNotNull(firstStatus);
        }

        [Test]
        public void TestGetUserStatuesesAboutSharan()
        {
            bool found = false;
            bool ended = false;
            long? maxID = long.MaxValue;
            int totalCount = 0;
            while (!found && !ended)
            {
                Statuses statuses = Microblog.GetUserStatuses(AldrickUserID, null, maxID, null, 20, StatusType.All, false);
                totalCount += statuses.Items.Count;

                if (statuses.Items.Count < 20)
                    ended = true;
                else
                    maxID = statuses.Items[statuses.Items.Count - 1].ID;

                foreach (StatusInfo status in statuses.Items)
                {
                    if (status.Text.Contains("#sharan#"))
                    {
                        found = true;
                        break;
                    }
                }
            }

            Assert.AreEqual(false, found);
            Assert.AreEqual(true, ended);
            Console.WriteLine("Total weibo count: " + totalCount);
        }

        [Test]
        public void TestGetPublicStatuses()
        {
            var result = Microblog.GetPublicStatuses(10);

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetFriendsStatuses()
        {
            var result = Microblog.GetFriendsStatuses();

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetMentions()
        {
            var result = Microblog.GetMentions();

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetFriends()
        {
            var users = Microblog.GetFriends(currentTestUserID);

            Assert.IsNotNull(users);
        }

        [Test]
        public void TestGetFollowers()
        {
            var users = Microblog.GetFollowers("苗拉");

            Assert.IsNotNull(users);
        }

        [Test]
        public void TestGetRateLimitStatus()
        {
            var result = Microblog.GetRateLimitStatus();

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetHotUsers()
        {
            var users = Microblog.GetHotUsers();

            Assert.IsNotNull(users);
        }

        [Test]
        public void TestGetSuggestedUsers()
        {
            var users = Microblog.GetSuggestedUsers();

            Assert.IsNotNull(users);
        }

        [Test]
        public void TestFollowUser()
        {
            try
            {
                Microblog.Unfollow(null, "Aldrick");
            }
            catch { }

            var result = Microblog.Follow("Aldrick");
            Assert.IsNotNull(result);

            var friendship = Microblog.GetFriendshipInfo(result.ID);
            Assert.IsNotNull(friendship);
            Assert.IsTrue(friendship.Source.Following);

            var exists = Microblog.ExistsFriendship(currentTestUserID, result.ID);
            Assert.IsTrue(exists);

            Microblog.Unfollow(null, "Aldrick");

            Microblog.Follow(result.ID);

            result = Microblog.Unfollow(result.ID);

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetFollowingOrFollowerUserIDs()
        {
            var result = Microblog.GetFollowingUserIDs();
            Assert.IsNotNull(result);

            result = Microblog.GetFollowerUserIDs();

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetPrivacy()
        {
            var result = Microblog.GetPrivacy();

            Assert.IsNotNull(result);
        }

        [Test]
        [ExpectedException(typeof(MicroblogException))]
        public void TestUpdatePrivacy()
        {
            var privacy = Microblog.GetPrivacy();

            Microblog.UpdatePrivacy(0, 0);
        }

        [Test]
        public void TestGetUserTags()
        {
            var result = Microblog.GetTags(AldrickUserID);

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestGetSuggestedTags()
        {
            var result = Microblog.GetSuggestedTags(12, 2);

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestTagsLifecycle()
        {
            var result = Microblog.CreateTags("Microblog", "WeiboAPI", "SINAAPI", "MicroblogAPI");

            Assert.IsNotNull(result);

            var result2 = Microblog.DeleteTags(result.Items[0], result.Items[1]);
            Assert.IsNotNull(result2);
            Assert.AreEqual(2, result2.Items.Count);

            Microblog.DeleteTag(result.Items[2]);
        }

        [Test]
        [ExpectedException(typeof(MicroblogException))]
        public void TestUpdateProfile()
        {
            var info = new UpdateProfileInfo();
            info.ScreenName = "A-Microblog-API-Test";
            info.Province = 31;
            info.City = 7;
            info.Gender = "f";
            info.Description = "I am a test machine.";

            // No permssion to call this API.
            var result = Microblog.UpdateProfile(info);

            Assert.IsNotNull(result);
        }

        [Test]
        public void TestFavoritesLifecycle()
        {
            var rnd = new Random();
            var text = "#MicroblogAPI# Test add to favorite 测试";
            var status = Microblog.PostStatus(new UpdateStatusInfo() { Status = text + rnd.Next().ToString() });
            var status2 = Microblog.PostStatus(new UpdateStatusInfo() { Status = text + rnd.Next().ToString() });
            Assert.IsNotNull(status);

            var result = Microblog.GetFavorites();
            Assert.IsNotNull(result);
            var favCount = result.Items.Count;

            var inFavoriteStatus = Microblog.AddToFavorite(status.ID);
            Assert.AreEqual(status.Text, inFavoriteStatus.Text);

            // Seems server uses an async way to perform the AddToFavorite operation.
            // So wait for a half second here.
            Thread.Sleep(1000);

            result = Microblog.GetFavorites();
            Assert.IsNotNull(result);
            Assert.IsTrue(result.Items.Count == favCount + 1);

            var deletedFromFav = Microblog.DeleteFromFavorite(status.ID);
            Assert.AreEqual(status.Text, deletedFromFav.Text);

            Microblog.AddToFavorite(status2.ID);
            result = Microblog.DeleteMultipleFromFavorite(status2.ID);
            Assert.IsNotNull(result);

            var deletedStatus = Microblog.DeleteStatus(status.ID);
            Assert.AreEqual(status.Text, deletedStatus.Text);

            var deletedStatus2 = Microblog.DeleteStatus(status2.ID);
            Assert.AreEqual(status2.Text, deletedStatus2.Text);
        }

        [Test]
        public void TestBlockLifecycle()
        {
            var result = Microblog.Block(AldrickUserID);
            Assert.IsNotNull(result);

            var isBlocked = Microblog.IsBlocked(AldrickUserID);
            Assert.IsTrue(isBlocked);

            var blockList = Microblog.GetBlockingList();
            Assert.IsNotNull(blockList);
            Assert.IsTrue(blockList.Items.Count > 0);
            var blockCount = blockList.Items.Count;

            var userInfo = Microblog.Unblock(AldrickUserID);
            Assert.IsNotNull(userInfo);

            var blockListIDs = Microblog.GetBlockingListIDs();
            Assert.IsNotNull(blockListIDs);
            Assert.IsTrue(blockListIDs.IDs.Count < blockCount);
        }

        [Test]
        public void TestTrendLifecycle()
        {
            var rnd = new Random();

            var hoourTrends = Microblog.GetHourTrends();
            Assert.IsNotNull(hoourTrends);

            var dayTrends = Microblog.GetDayTrends();
            Assert.IsNotNull(dayTrends);

            var weekTrends = Microblog.GetWeekTrends();
            Assert.IsNotNull(weekTrends);

            var trendStatuses = Microblog.GetTrendStatuses("MicroblogAPI");
            Assert.IsNotNull(trendStatuses);

            var userTrends = Microblog.GetUserTrends(currentTestUserID);
            Assert.IsNotNull(userTrends);

            var followedTrendID = Microblog.FollowTrend("MicroblogAPI" + rnd.Next().ToString());

            var unfollowed = Microblog.UnfollowTrend(followedTrendID);
            Assert.IsTrue(unfollowed);
        }

        [Test]
        public void TestShortUrlLifecycle()
        {
            var weibo = "http://open.weibo.com";
            var result = Microblog.ConvertToShortUrls(weibo, "http://open.weibo.com/wiki/Short_url/shorten", "http://open.weibo.com/wiki/API%E6%96%87%E6%A1%A3");
            Assert.IsNotNull(result);
            Assert.IsTrue(result.Items.Count == 3);

            var weiboShort = result.Items[0].ShortUrl;
            result = Microblog.ConvertToLongUrls(weiboShort);
            Assert.IsTrue(result.Items[0].LongUrl == weibo);

            var sharedCount = Microblog.GetShortUrlSharedCount(weiboShort);
            Assert.IsNotNull(sharedCount);
            Assert.IsTrue(sharedCount.Items.Count == 1);

            var sharedStatues = Microblog.GetShortUrlSharedStatuses(weiboShort);
            Assert.IsNotNull(sharedStatues);

            var commentCount = Microblog.GetShortUrlCommentCount(weiboShort);
            Assert.IsNotNull(commentCount);

            var sharedComments = Microblog.GetShortUrlComments(weiboShort);
            Assert.IsNotNull(sharedComments);
        }
    }

    public class FakeErrorHandler : IResponseErrorHandler
    {
        public void Handle(ResponseErrorData errorData)
        {
            throw new NotImplementedException();
        }
    }
}
